project(
  'hdlConvertor',
  ['cpp', 'cython'],
  version: '2.3',
  license: 'MIT',
  meson_version: '>=1.1.0',
  default_options: ['cpp_std=c++17'],
)

python_prog = find_program(['python3', 'python'])

##############################################################################################
# Lookup all dependencies and prepare common variables
##############################################################################################
# https://meson-python.readthedocs.io/en/latest/reference/config-settings.html
# https://github.com/shenxianpeng/gcov-example
py3_mod = import('python')
py3 = py3_mod.find_installation(required: true)
py3_dep = py3.dependency()
# Java is used to generate source files for parsers, it is required only for installation
cc = meson.get_compiler('cpp')

EXTRA_CXX_FLAGS = []
EXTRA_LD_FLAGS = []
if meson.get_compiler('cpp').get_id() == 'msvc'
	EXTRA_CXX_FLAGS += ['-MP /wd4251', '/bigobj'] # https://github.com/antlr/antlr4/blob/dev/runtime/Cpp/demo/CMakeLists.txt
	# using /MD flag for antlr4_runtime (for Visual C++ compilers only)
elif host_machine.system() == 'cygwin'
	EXTRA_CXX_FLAGS += ['-Wa,-mbig-obj']
elif host_machine.system() == 'linux'
    EXTRA_CXX_FLAGS += ['-Wall', '-pedantic', '-W', '-Wno-attributes']
endif

# [fixme] use of local antlr4-runtime dissabled because check for version does not work
#antlr4_cpp_dep = cc.find_library('antlr4-runtime', required : false)
#if not antlr4_cpp_dep.found()
	message('atempting to download antrl4-complete.jar and antlr4-runtime for C++ because installation was not found')
	cmake = import('cmake')
	
	antlr4_runtime_opt = cmake.subproject_options()
	antlr4_runtime_opt.add_cmake_defines({
	  'ANTLR_BUILD_CPP_TESTS': false,
	  'ANTLR_BUILD_SHARED': false,
	  'ANTLR4_INSTALL': false,
	  'CMAKE_CXX_FLAGS_RELEASE': ' '.join(EXTRA_CXX_FLAGS + ['-Wno-overloaded-virtual', '-Wno-unused-parameter']),
	  'CMAKE_POSITION_INDEPENDENT_CODE': true,
	  'CMAKE_BUILD_TYPE': 'Release',
	})
	
	antlr4_runtime_opt.set_install(false) # because meson-python does not know where to install it
	antlr4_runtime_proj = cmake.subproject('antlr4-runtime', options: antlr4_runtime_opt)
	antlr4_cpp_dep = antlr4_runtime_proj.dependency('antlr4_static')
	antlr4_cpp_version = '4.13.2' # :note: must match version in antlr4-runtime.wrap
	import('java') # to check that java is installed
	antlr4_jar = join_paths(meson.current_build_dir() , 'antlr4-complete.jar')
	fs = import('fs')
	if not fs.exists(antlr4_jar)
		run_command(python_prog, 'utils/download.py',
			f'https://www.antlr.org/download/antlr-@antlr4_cpp_version@-complete.jar', antlr4_jar,
			check: true) # '--hash', 'md5', 'c9c8b566a7fcf8ef80e229f14b154a26', 
    endif
	antlr4_java = find_program('utils/antlr4-complete.sh') # an extra script so we do not need to write all arguments everytime
#else
#	antlr4_cpp_inc = include_directories('/usr/include/antlr4-runtime/')
#	antlr4_cpp_dep = cc.find_library('antlr4-runtime', header_include_directories: antlr4_cpp_inc, has_headers: 'antlr4-runtime.h', required : false)
#    # redeclare because include_dir somehow is not in dependency
#	antlr4_cpp_dep = declare_dependency(dependencies: [antlr4_cpp_dep], include_directories: antlr4_cpp_inc)
#	antlr4_java = find_program('antlr4', required : true)
#endif

cp = find_program('cp', required : true)


##############################################################################################
# build of antlr4 generated parsers
##############################################################################################

#name folder_name generate_visitor generate_listener lexer_parser_separate
# * name the name of the parser grammar and parser itself
# * folder_name name of folder where convertor is stored
#	(which is using this parser)
ANTLR_PARSERS = [
 ['sv2017', 'svConvertor', false, false],
 ['verilogPreproc', 'verilogPreproc', true, false],
 ['vhdl', 'vhdlConvertor', false, false],
]
curSrcDir = meson.current_source_dir()
mainIncludeDir = 'include/'
mainIncludeDir_inc = include_directories(mainIncludeDir)
all_parser_libs = []
all_parser_deps = []
all_parser_header_targets = []

foreach parserTuple : ANTLR_PARSERS
	name = parserTuple[0]
	folder_name = parserTuple[1]
	generate_visitor = parserTuple[2]
	generate_listener = parserTuple[3]
	message(f'Preparing build of antlr4 parser @name@')
	antlr_gen_outputs = [
		f'@name@Lexer.cpp',
	    f'@name@Lexer.h',
		f'@name@Parser.cpp',
		f'@name@Parser.h',
    ]

	# explicitely named all header files which are generated by ANTLR

	antlr_gen_args = ['-Dlanguage=Cpp',]
	if generate_visitor
		antlr_gen_args += '-visitor'
		antlr_gen_outputs += [
			f'@name@ParserBaseVisitor.h',
			f'@name@ParserVisitor.h',
		]
	else
	    antlr_gen_args += '-no-visitor'
	endif
	if generate_listener
		antlr_gen_args += '-listener'
		antlr_gen_outputs += [
			f'@name@ParserBaseListener.h',
			f'@name@ParserListener.h',
		]
	else
	 	antlr_gen_args += '-no-listener'
	endif

	# create source directory
	# create include directory
	# run antlr to generate parser
	# mv headers to include directory
	# [todo] does not supports spaces in filenames
	GRAMMAR_FILES = [join_paths(curSrcDir, 'grammars', f'@name@Lexer.g4'),
	                 join_paths(curSrcDir, 'grammars', f'@name@Parser.g4')]
	antlr_parser_parser_src_gen = custom_target(f'@name@_src_gen',
	    input : GRAMMAR_FILES,
	    output : antlr_gen_outputs,
	    command : [antlr4_java, ] + antlr_gen_args +
	              ['-package', f'@name@_antlr', '-encoding', 'utf-8', '-o', meson.current_build_dir()] + GRAMMAR_FILES)
  	
  	# run copy of header files
  	generated_headers_abs = []
  	generated_headers = []
	foreach f: antlr_gen_outputs
		if f.endswith('.h')
			generated_headers_abs += join_paths(meson.current_build_dir(), f)
            generated_headers += f
		endif
	endforeach
	genIncludeDir = join_paths('include', 'hdlConvertor', folder_name, f'@name@Parser')
	subdir(genIncludeDir)

	# Add the header copy target to our list of dependencies
	all_parser_header_targets += antrl_parser_headers

	parser_cpp_src = run_command(python_prog, 'utils/rec_glob.py', join_paths('src', folder_name), '*.cpp', check:true)\
    	.stdout().strip().split('\n')
	
    parser_lib = static_library(name,
	    parser_cpp_src + antlr_parser_parser_src_gen + antrl_parser_headers,
        cpp_args: ['-Wno-unused-parameter', '-Wno-overloaded-virtual'] + EXTRA_CXX_FLAGS,
        dependencies: [antlr4_cpp_dep],
        include_directories: [mainIncludeDir_inc, include_directories(genIncludeDir)],
    )
    all_parser_libs += parser_lib
    parser_lib_dependency = declare_dependency(
         link_with : [parser_lib],)
    all_parser_deps += parser_lib_dependency
endforeach

subdir('src')

if get_option('python_package')
	subdir('hdlConvertor')
endif

# if tests files are in the package mark them as test data
test_data = run_command(python_prog, 'utils/rec_glob.py', 'tests', '*', check:true)\
	.stdout().strip().split('\n')
message('test_data:\n' + '\n'.join(test_data))
	
install_data(test_data, install_tag : 'tests')

